﻿
using System.IO;
using System.Text;
using System.Windows.Media.Imaging;
using Microsoft.WindowsAPICodePack.Shell;

namespace BackupGUI
{
    using System;
    using System.Diagnostics;
    using System.Reflection;
    using System.Security.Principal;
    using System.ServiceProcess;
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using BackupLib;
    using BackupLib.Remoting;
    using Microsoft.WindowsAPICodePack;
    using System.ComponentModel;
    using System.Windows.Controls;
    using Microsoft.WindowsAPICodePack.Shell;
    using NotifyIcon = System.Windows.Forms.NotifyIcon;
    using ToolTipIcon = System.Windows.Forms.ToolTipIcon;

    /// <summary>
    /// Interaktionslogik für Status.xaml
    /// </summary>
    public partial class Status
    {
        private BackupEventSink eventsink;
        private IBackupTask Server;
        private Storyboard IconAnimation;
        private NotifyIcon NotifyIcon;

        private delegate void FinishedDelegate(object sender, BackupFinishedEventArgs e);
        private delegate void StartDelegate(object sender, BackupEventArgs e);
        private delegate void FileDelegate(object sender, BackupFileEventArgs e);

        SolidColorBrush BrushRedFill = new SolidColorBrush(Colors.Red);
        SolidColorBrush BrushGreenFill = new SolidColorBrush(Color.FromRgb(0x01, 0xD3, 0x28));

        public Status()
        {
            InitializeComponent();

            IPCHelper.RegisterClient();
            Server = new ServerMethods();

            NotifyIcon=new NotifyIcon();
            NotifyIcon.DoubleClick += NotifyIconDoubleClick;
            NotifyIcon.MouseClick += NotifyIconMouseClick;
            NotifyIcon.Icon = UIHelper.LoadIcon("Backup");
            NotifyIcon.Text = "Sicherungsstatus";
            NotifyIcon.Visible = true;

            IconAnimation = Resources["IconAnimation"] as Storyboard;

            CheckServiceState();

            if (Server.IsProcessing)
            {
                //TODO: handle still running backup
            }

            if (Server.IsProcessing)
            {
                btnPause.Content = "Pause";
            }

            eventsink = new BackupEventSink(Server);
            eventsink.OnFile += ProjectOnFile;
            eventsink.OnStart += ProjectOnStart;
            eventsink.OnStop += ProjectOnStop;

            if (!IsAdmin())
            {
                mnuBackup.Icon = GetShieldIcon();
                mnuSettings.Icon = GetShieldIcon();
                mnuService.Icon = GetShieldIcon();
            }
            var args = Environment.GetCommandLineArgs();
            if (args.Length == 2)
            {
                CommandHandler(args[1],true);
            }
        }

        private void CheckServiceState()
        {
#if !(DEBUG)
            ServiceController service = new ServiceController("BackupSvc");
            if (service.Status != ServiceControllerStatus.Running)
            {
                NotifyUser("Dienst inaktiv", "Versuche Backup-Dienst neu zu starten.");
                CommandHandler(mnuService);
            }
#endif
        }

        private void RestartService()
        {
            ServiceController service = new ServiceController("BackupSvc");
            TimeSpan timeout = TimeSpan.FromSeconds(15);
            if (service.Status == ServiceControllerStatus.Running)
            {
                service.Stop();
                service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
            }
            service.Start();
            service.WaitForStatus(ServiceControllerStatus.Running, timeout);
        }

        private Image GetShieldIcon()
        {
            StockIcon iconShield=new StockIcon(StockIconIdentifier.Shield, StockIconSizes.Small, false, false);
            Image img = new Image();
            img.Tag = iconShield;
            img.Stretch = Stretch.None;
            img.Source = iconShield.BitmapSource;
            return img;
        }

        private bool IsAdmin()
        {
            WindowsIdentity wi = WindowsIdentity.GetCurrent();
            if (wi != null)
            {
                WindowsPrincipal wp = new WindowsPrincipal(wi);

                return wp.IsInRole(WindowsBuiltInRole.Administrator);
            }
            throw new System.Security.SecurityException("Can't get identity.");
        }

        void NotifyIconMouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                Menu.IsOpen = true;
            }
        }

        void NotifyIconDoubleClick(object sender, EventArgs e)
        {
            ToggleVisibility();
        }

        void IconChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
            {
                ImageSource imageSource = e.NewValue as ImageSource;
                //NotifyIcon.Icon = UIHelper.ImageSource2Icon(imageSource);
            }
        }


        public void ToggleVisibility()
        {
            if (Visibility!=Visibility.Visible)
            {
                Visibility = Visibility.Visible;
            }
            else
            {
                Visibility = Visibility.Hidden;
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
        }

        void ProjectOnStop(object sender, BackupFinishedEventArgs e)
        {
            if(Dispatcher.CheckAccess())
            {
                IconAnimation.Stop();
                btnPause.Content = "Start";
                var fs=File.OpenWrite("debug.log");
                TextWriter tw = new StreamWriter(fs);
                tw.WriteLine(log.ToString());
                tw.Close();
                NotifyUser("Backup abgeschlossen",
                           "Erfolgreich: " + e.Successful + "\nFehlgeschlagen: " + e.Failed + "\nÜbersprungen: " +
                           e.Ignored);
            }
            else
            {
                FinishedDelegate finishedDelegate = ProjectOnStop;
                Dispatcher.BeginInvoke(finishedDelegate, new []{sender,e});
            }
        }

        void NotifyUser(string title,string message)
        {
            if (string.IsNullOrEmpty(title)) return;
            if (string.IsNullOrEmpty(message)) message=" ";
            if (IsVisible)
            {
#if (DEBUG)
                MessageBox.Show(message, title);
#else
                TaskDialog.Show(title, title, message);
#endif
            }
            else
            {
                NotifyIcon.ShowBalloonTip(1000, title, message, ToolTipIcon.Info);
            }
        }

        void ProjectOnStart(object sender, BackupEventArgs e)
        {
            if (Dispatcher.CheckAccess())
            {
                IconAnimation.Begin();
                btnPause.Content = "Pause";
                Visibility = Visibility.Visible;
            }
            else
            {
                StartDelegate startDelegate = ProjectOnStart;
                Dispatcher.BeginInvoke(startDelegate, new[] { sender, e });
            }
        }

        public void ProjectOnFile(object sender, BackupFileEventArgs e)
        {
            if (Dispatcher.CheckAccess())
            {
                progressBar.Value = e.Progress;
                if (e.Failed)
                {
                    if (progressBar.Foreground==BrushGreenFill)
                        progressBar.Foreground = BrushRedFill;
                    log.AppendLine(e.Path);
                    log.AppendLine(e.Details);
                }
                else
                {
                    if (progressBar.Foreground == BrushRedFill)
                        progressBar.Foreground = BrushGreenFill;
                }
            }
            else
            {
                FileDelegate fileDelegate = ProjectOnFile;
                Dispatcher.BeginInvoke(fileDelegate, new[] { sender, e });
            }
        }

        private StringBuilder log= new StringBuilder();

        private void btnHide_Click(object sender, RoutedEventArgs e)
        {
            CommandHandler(mnuStatus);
        }

        private void btnPause_Click(object sender, RoutedEventArgs e)
        {
            CommandHandler(mnuBackup);
        }

        private void CommandHandler(MenuItem command)
        {
            CommandHandler(command.Name, command.Icon != null);
        }

        private void CommandHandler(string command, bool requireAdmin)
        {
            if (requireAdmin&&!IsAdmin())
            {
                try
                {
                    Process process = new Process();
                    process.StartInfo.FileName = Assembly.GetEntryAssembly().Location;
                    process.StartInfo.Arguments = command;
                    process.StartInfo.Verb = "runas";
                    process.Start();
                    Close();
                }
                catch (Win32Exception)
                { }
                return;
            } 
            
            switch (command)
            {
                case "mnuBackup":
                    if (Server.IsProcessing)
                    {
                        Server.Pause();
                    }
                    else
                    {
                        RunBackup();
                    } 
                    break;
                case "mnuCancel":
                    Server.Stop();
                    break; 
                case "mnuStatus":
                    ToggleVisibility();
                    break;
                case "mnuService":
                    RestartService();
                    break;
                case "mnuSettings":
                    ProjectSettings projectSettings = new ProjectSettings();
                    projectSettings.ShowDialog();
                    Server.ReloadProject();
                    break;
                case "mnuExit":
                    Close();
                    Environment.Exit(0);
                    break;
            }
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            MenuItem menuItem = (MenuItem) sender;
            
            CommandHandler(menuItem);
        }

        private void RunBackup()
        {
            Server.ReloadProject();
            Server.DoBackup();
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            CommandHandler(mnuCancel);
        }

        private void StatusWindow_Closing(object sender, CancelEventArgs e)
        {
            NotifyIcon.Visible = false;
        }
    }
}
